package core.algorithms;

import java.util.List;

import core.interfaces.IBooleanOperator;
import core.interfaces.IState;

public class FirstChoiceHCWithRandomRestart<T> extends HillClimbing<T>
{
	/**
	 * 
	 */
	private static final long serialVersionUID = -2105979216250614326L;
	int m_drawLimit; //number of attempts before random restart

	public FirstChoiceHCWithRandomRestart(SearchParameters<T> searchParameters)
	{
		super(searchParameters);

		
	}
	
	@Override public void initAlgorithm(core.algorithms.SearchParameters<T> searchParameters)
	{
		super.initAlgorithm(searchParameters);
		
		m_drawLimit = searchParameters.getDrawLimit();
		m_SearchResults = new SearchResults<T>(null, -1, false, 0);
	};
	
	public SearchResults<T> doAlgorithm(IState<T> initialState)
	{
		
		IState<T> currentState = initialState;
		double currentHeuristicValue = super.callHeuristicFunction(currentState);

		//main iteration loop:
		while (isDoAnotherIteration(m_SearchParameters.isBoundHeuristicCalls()))
		{
			saveBestState(currentState, currentHeuristicValue);
			
			boolean doRandomRestart = true;
			List<? extends IBooleanOperator> possibleOperators = currentState.getPossibleOperators();
			
			// first choice HC implementation:
			int draws = 0;
			while(draws < m_drawLimit)
			{
				IBooleanOperator operator = drawOperator(possibleOperators);

				// try the current operator
				currentState.doOperator(operator);
				
				// get the value for the new node
				double neighbourValue = super.callHeuristicFunction(currentState);
				
				// check current results
				if (neighbourValue > currentHeuristicValue) 
				{
					//do step
					doRandomRestart = false;
					currentHeuristicValue = neighbourValue;
					break;
					
				}
				
				//no improvement try another operator
				currentState.doOperator(operator);
				++draws;
			}
			if(doRandomRestart)
			{
				doRandomRestart(currentState, possibleOperators);
				currentHeuristicValue = super.callHeuristicFunction(currentState);
			}
			super.stepFinished();
		}
		return new SearchResults<T>(
				getSearchResults().getFinalState(),
				getSearchResults().getFinalStateValue(),
				(m_StepsTaken == getSearchParameters().getMaximumHeuristicCalls()),
				m_StepsTaken);
	}

	private void doRandomRestart(IState<T> currentState,
			List<? extends IBooleanOperator> possibleOperators)
	{
		currentState.reset();

		//select a random state
		int draws = m_Randomizer.nextInt(possibleOperators.size());
		for(int i = 0; i < draws; i++)
		{
			int randomOperator = m_Randomizer.nextInt(possibleOperators.size());
			currentState.doOperator(possibleOperators.get(randomOperator));
		}
//		if(currentState.shortcutOperatorExists())
//		{
//			currentState.doShortcutOperator();
//		}
		
	}

	private IBooleanOperator drawOperator(
			List<? extends IBooleanOperator> possibleOperators)
	{
		int index = m_Randomizer.nextInt(possibleOperators.size());
		return possibleOperators.get(index);
	}

	@Override
	public String getAlgorithmName()
	{
		return "FIRST CHOICE RANDOM RESTART HC";
	}
}
